android 自定义预制APP分区
1.先要能被PMS扫描到,在构造函数里添加一条扫描记录,还要设置加载一些库的路径,比如:
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
......
File oem3rdAppDir = new File(Environment.getOemDirectory(), "preloadapp");
scanDirLI(oem3rdAppDir, 0, scanFlags, 0);
// Remove disable package settings for updated system apps that were
// removed via an OTA. If the update is no longer present, remove the
// app completely. Otherwise, revoke their system privileges.
for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {
PackageParser.Package deletedPkg = mPackages.get(deletedAppName);
mSettings.removeDisabledSystemPackageLPw(deletedAppName);
scanDirLI(oem3rdAppDir, 0, scanFlags, 0);
// Remove disable package settings for updated system apps that were
// removed via an OTA. If the update is no longer present, remove the
// app completely. Otherwise, revoke their system privileges.
for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {
PackageParser.Package deletedPkg = mPackages.get(deletedAppName);
mSettings.removeDisabledSystemPackageLPw(deletedAppName);
......
}
private static void setNativeLibraryPaths(PackageParser.Package pkg, File appLib32InstallDir) {
......
boolean isOem3rdApp = codePath.startsWith("/oem/preloadapp") ? true : false;
if (isApkFile(codeFile) || isOem3rdApp) {。。。。。。}
......
boolean isOem3rdApp = codePath.startsWith("/oem/preloadapp") ? true : false;
if (isApkFile(codeFile) || isOem3rdApp) {。。。。。。}
2.直接扫描进去可能会遇到一下问题,比如APP启动报错,卸载后重启会又加载到APP等。
2.1 APP启动报错,这可能涉及到证书的问题,预制APP可以不用检查证书,可以在 PackageParser.java 里添加如下:
private static void collectCertificates(Package pkg, File apkFile, int parseFlags)
throws PackageParserException {
throws PackageParserException {
......
StrictJarFile jarFile = null;
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "strictJarFileCtor");
// Ignore signature stripping protections when verifying APKs from system partition.
// For those APKs we only care about extracting signer certificates, and don't care
// about verifying integrity.
boolean signatureSchemeRollbackProtectionsEnforced =
(parseFlags & PARSE_IS_SYSTEM_DIR) == 0;
boolean IsPrebuiltApp = apkPath != null
&& apkPath.startsWith("/oem/preloadapp");
jarFile = new StrictJarFile(
apkPath,
!verified, // whether to verify JAR signature
IsPrebuiltApp ? false : signatureSchemeRollbackProtectionsEnforced);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "strictJarFileCtor");
// Ignore signature stripping protections when verifying APKs from system partition.
// For those APKs we only care about extracting signer certificates, and don't care
// about verifying integrity.
boolean signatureSchemeRollbackProtectionsEnforced =
(parseFlags & PARSE_IS_SYSTEM_DIR) == 0;
boolean IsPrebuiltApp = apkPath != null
&& apkPath.startsWith("/oem/preloadapp");
jarFile = new StrictJarFile(
apkPath,
!verified, // whether to verify JAR signature
IsPrebuiltApp ? false : signatureSchemeRollbackProtectionsEnforced);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
......
2.2 卸载后重启会又加载到APP,因为系统每次启动都会去扫描,所以出现此问题的解决思路是在卸载之后把改APP记录到某个文件,开机后每次扫描的时候做个判断,如果是被卸载的预制APP,则直接返回,比如:
private boolean deletePackageLIF(String packageName, UserHandle user,
boolean deleteCodeAndResources, int[] allUserHandles, int flags,
PackageRemovedInfo outInfo, boolean writeSettings,
PackageParser.Package replacingPackage) {
boolean deleteCodeAndResources, int[] allUserHandles, int flags,
PackageRemovedInfo outInfo, boolean writeSettings,
PackageParser.Package replacingPackage) {
......
if (isSystemApp(ps)) {
if (DEBUG_REMOVE) Slog.d(TAG, "Removing system package: " + ps.name);
// When an updated system application is deleted we delete the existing resources
// as well and fall back to existing code in system partition
ret = deleteSystemPackageLIF(ps.pkg, ps, allUserHandles, flags, outInfo, writeSettings);
} else {
if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package: " + ps.name);
if(ps.pkg != null && ps.pkg.baseCodePath != null){
String path = ps.pkg.baseCodePath.substring(0, ps.pkg.baseCodePath.lastIndexOf("/"));
if (DEBUG_REMOVE) Slog.d(TAG, "Removing system package: " + ps.name);
// When an updated system application is deleted we delete the existing resources
// as well and fall back to existing code in system partition
ret = deleteSystemPackageLIF(ps.pkg, ps, allUserHandles, flags, outInfo, writeSettings);
} else {
if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package: " + ps.name);
if(ps.pkg != null && ps.pkg.baseCodePath != null){
String path = ps.pkg.baseCodePath.substring(0, ps.pkg.baseCodePath.lastIndexOf("/"));
这里根据卸载APP的path判断是否是需要预留的APP,如果是则记录到文件
}
ret = deleteInstalledPackageLIF(ps, deleteCodeAndResources, flags, allUserHandles,
outInfo, writeSettings, replacingPackage);
}
......
}
private PackageParser.Package scanPackageLI(PackageParser.Package pkg, File scanFile,
final int policyFlags, int scanFlags, long currentTime, @Nullable UserHandle user)
throws PackageManagerException {
这里可以判断是否是已经卸载的预制APP,如果是则直接返回,不用继续加载
if(。。。。。。)return pkg;
final int policyFlags, int scanFlags, long currentTime, @Nullable UserHandle user)
throws PackageManagerException {
这里可以判断是否是已经卸载的预制APP,如果是则直接返回,不用继续加载
if(。。。。。。)return pkg;
。。。。。。
}